#ifndef INTERFACE_HPP
#define INTERFACE_HPP

#include "simple.hpp"

template <typename T, typename Enabled = std::nullptr_t>
struct has_offset_type : std::false_type {};
template <typename T>
struct has_offset_type<T, decltype(std::declval<T::offset_type>(), nullptr)> :
	std::true_type {};

template <typename Offset>
class i_movable
{
	protected:
	~i_movable() = default;
	public:
	using offset_type = Offset;
	virtual i_movable& operator+=(const Offset&) = 0;
};

template <typename Offset>
i_movable<Offset>& operator+=(i_movable<Offset>& self, const Offset& offset)
{
	return self += offset;
}

template <typename Bound>
class i_bounds
{
	protected:
	~i_bounds() = default;
	public:
	using bound_type = Bound;
	virtual Bound lower() const = 0;
	virtual Bound upper() const = 0;
};

template <typename Bound>
Bound lower(const i_bounds<Bound>& self)
{ return self.lower(); }
template <typename Bound>
Bound upper(const i_bounds<Bound>& self)
{ return self.upper(); }

template <typename T>
class i_movable_bounds : public i_bounds<T>, public i_movable<T>
{
	protected:
	~i_movable_bounds() = default;
};

class i_graphic
{
	protected:
	~i_graphic() = default;
	public:
	virtual void draw(const graphical::surface&) = 0;
};

class i_interactive
{
	protected:
	~i_interactive() = default;
	public:
	virtual void update(const interactive::event&) = 0;
};

class i_focusable
{
	protected:
	~i_focusable() = default;
	public:

	enum direction
	{
		prev = -1,
		self = 0,
		next = 1
	};

	virtual bool focus() const = 0;
	virtual void drop_focus() = 0;
	virtual bool focus(direction) = 0;
	virtual bool focus_on(const i_focusable&) = 0;
};

// free function alternatives... double the work double the fun??
// or should these be the only ones
// initial rationale: interface to work with reference wrapper, that implicitly converts to reference
inline bool focus(const i_focusable& self) {return self.focus(); }
inline void drop_focus(i_focusable& self) { self.drop_focus(); }
inline bool focus(i_focusable& self, i_focusable::direction direction)
{ return self.focus(direction); }
inline bool focus_on(i_focusable& self, const i_focusable& target) { return self.focus_on(target); }

class i_ui_object
{
	public:
	virtual ~i_ui_object() = default;
};

#endif /* end of include guard */
